using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text.Json;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using Betalgo.Ranul.OpenAI;
using Betalgo.Ranul.OpenAI.Managers;
using Betalgo.Ranul.OpenAI.ObjectModels.RequestModels;
using HengTong.Model;
using HengTong.Model.Db.SupplyChain.Material;
using HengTong.Model.Db.SupplyChain.Warehouse;
using HengTong.Model.Gpt;
using HengTong.Model.Interfaces;
using HengTong.ViewModel.SupplyChain.SysMaterialSkuVms;
using HengTong.ViewModel.SupplyChain.SysMaterialVms;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using TiaoTaoHelper.Extension.String;
using TiaoTaoHelper.Models;
using TiaoTaoHelper.Wtm.Models;
using UUIDNext;
using WalkingTec.Mvvm.Core;
using WalkingTec.Mvvm.Core.Extensions;

namespace HengTong.Services;

public class DataSyncService(ILogger<DataSyncService> logger, WTMContext context, IThirdPartyDataProvider dataProvider, IServiceProvider serviceProvider)
{

    /// <summary>
    /// 同步EAS计量单位组数据
    /// </summary>
    /// <param name="disableNotExist">EAS中不存在的数据将会被禁用</param>
    public async Task<Result<int>> MeasureUnitGroupSync(bool disableNotExist = false)
    {
        try
        {
            var raw = await dataProvider.GetMeasureUnitGroupData();
            var data = await context.DC.Set<SysMeasureUnitGroup>()
                .AsNoTracking()
                .ToListAsync();
            var list  = new List<SysMeasureUnitGroup>();
            var syncIds = new List<Guid>();
            foreach (var element in raw)
            {
                var group = data.FirstOrDefault(e => e.ErpId == element.ErpId);
                if (group == null)
                {
                    //EAS数据转换为系统数据
                    var item = new SysMeasureUnitGroup
                    {
                        ID = Uuid.NewDatabaseFriendly(Database.SqlServer),
                        Name = element.Name,
                        Code = element.ErpId,
                        ErpId = element.ErpId,
                        Description = element.Description,
                        State = CommonState.启用,
                        CreateTime = element.CreateTime ?? DateTime.Now,
                        UpdateTime = element.UpdateTime ?? DateTime.Now,
                        CreateBy = context.LoginUserInfo?.ITCode ?? "system",
                        UpdateBy = context.LoginUserInfo?.ITCode ?? "system"
                    };
                    if (!string.IsNullOrWhiteSpace(element.ParentName))
                    {
                        var parent = data.FirstOrDefault(e => e.ErpId == element.ParentName);
                        if (parent != null)
                        {
                            item.ParentId = parent.ID;
                        }
                        else
                        {
                            logger.LogWarning("EAS计量单位组数据同步: 未找到上级计量单位组, {@group}", element);
                            continue;
                        }
                    }
                    list.Add(item);
                    data.Add(item);
                }
                else
                {
                    syncIds.Add(group.ID);
                }
            }
            if (list.Any())
            {
                await context.DC.Set<SysMeasureUnitGroup>().AddRangeAsync(list);
                await context.DC.SaveChangesAsync();
                logger.LogInformation("EAS计量单位组数据同步: 成功同步{count}条数据", list.Count);
                if (disableNotExist)
                {
                    //禁用所有未同步的数据
                    var notSyncIds = data.Select(e => e.ID).Except(syncIds).ToList();
                    if (notSyncIds.Any())
                    {
                        await context.DC.Set<SysMeasureUnitGroup>()
                            .Where(e => notSyncIds.Contains(e.ID))
                            .ExecuteUpdateAsync(e => e
                                .SetProperty(x => x.State, x => CommonState.禁用)
                                .SetProperty(x => x.Remark, x => "EAS不存在该数据, 自动禁用")
                            );
                        logger.LogInformation("EAS计量单位组数据同步: 成功禁用{count}条数据", notSyncIds.Count);
                    }
                }
            }
            else
            {
                logger.LogInformation("EAS计量单位组数据同步: 无新数据需要同步");
            }
            return new Result<int>(list.Count);
        }
        catch (Exception e)
        {
            logger.LogError(e, $"计量单位组数据同步失败, {e.Message}");
            return new Result<int>(e.Message);
        }
    }
    
    /// <summary>
    /// 同步EAS计量单位数据
    /// </summary>
    public async Task<Result<int>> MeasureUnitSync()
    {
        try
        {
            var raw = await dataProvider.GetMeasureUnitData();
            raw = raw.OrderBy(e => e.ErpId).ToArray();
            var data = await context.DC.Set<SysMeasureUnit>()
                .AsNoTracking()
                .ToArrayAsync();
            var groupData = await context.DC.Set<SysMeasureUnitGroup>()
                .AsNoTracking()
                .ToArrayAsync();
            var list  = new List<SysMeasureUnit>();
            foreach (var element in raw)
            {
                var unit = data.FirstOrDefault(e => e.ErpId == element.ErpId);
                if (unit == null)
                {
                    //EAS数据转换为系统数据
                    var item = new SysMeasureUnit
                    {
                        Name = element.Name,
                        Code = element.ErpId,
                        ErpId = element.ErpId,
                        Description = element.Description,
                        State = CommonState.启用,
                        CreateTime = element.CreateTime ?? DateTime.Now,
                        UpdateTime = element.UpdateTime ?? DateTime.Now,
                        CreateBy = context.LoginUserInfo?.ITCode ?? "system",
                        UpdateBy = context.LoginUserInfo?.ITCode ?? "system"
                    };
                    if (!string.IsNullOrWhiteSpace(element.GroupName))
                    {
                        var group = groupData.FirstOrDefault(e => e.ErpId == element.GroupName);
                        if (group != null)
                        {
                            item.MeasureUnitGroupId = group.ID;
                        }
                        else
                        {
                            logger.LogWarning("EAS计量单位数据同步: 未找到所属计量单位组, {@unit}", element);
                            continue;
                        }
                    }
                    list.Add(item);
                }
            }
            if (list.Any())
            {
                await context.DC.Set<SysMeasureUnit>().AddRangeAsync(list);
                await context.DC.SaveChangesAsync();
                logger.LogInformation("EAS计量单位数据同步: 成功同步{count}条数据", list.Count);
            }
            else
            {
                logger.LogInformation("EAS计量单位数据同步: 无新数据需要同步");
            }
            return new Result<int>(list.Count);
        }
        catch (Exception e)
        {
            logger.LogError(e, $"计量单位数据同步失败, {e.Message}");
            return new Result<int>(e.Message);
        }
    }


    /// <summary>
    /// 同步EAS物料分组
    /// </summary>
    public async Task<Result<int>> MaterialGroupSync()
    {
        try
        {
            var raw = await dataProvider.GetMaterialGroupData();
            var data = await context.DC.Set<SysMaterialGroup>()
                .AsNoTracking()
                .ToListAsync();
            var list  = new List<SysMaterialGroup>();
            foreach (var element in raw.OrderBy(e => e.Level))
            {
                if (data.All(e => e.ErpId != element.ErpId))
                {
                    //EAS数据转换为系统数据
                    var item = new SysMaterialGroup
                    {
                        ID = Uuid.NewDatabaseFriendly(Database.SqlServer),
                        Name = element.Name,
                        Code = element.ErpId,
                        ErpId = element.ErpId,
                        Description = element.Description,
                        State = CommonState.启用,
                        Level = element.Level,
                        CreateTime = element.CreateTime ?? DateTime.Now,
                        UpdateTime = element.UpdateTime ?? DateTime.Now,
                        CreateBy = context.LoginUserInfo?.ITCode ?? "system",
                        UpdateBy = context.LoginUserInfo?.ITCode ?? "system"
                    };
                    if (!string.IsNullOrWhiteSpace(element.ParentName))
                    {
                        var parent = data.FirstOrDefault(e => e.ErpId == element.ParentName);
                        if (parent != null)
                        {
                            item.ParentId = parent.ID;
                        }
                        else
                        {
                            logger.LogWarning("EAS物料分类数据同步: 未找到上级物料分类, {@group}", element);
                            continue;
                        }
                    }
                    list.Add(item);
                    data.Add(item);
                }
            }
            if (list.Any())
            {
                await context.DC.Set<SysMaterialGroup>().AddRangeAsync(list);
                await context.DC.SaveChangesAsync();
                logger.LogInformation("EAS物料分类数据同步: 成功同步{count}条数据", list.Count);
            }
            else
            {
                logger.LogInformation("EAS物料分类数据同步: 无新数据需要同步");
            }
            return new Result<int>(list.Count);
        }
        catch (Exception e)
        {
            logger.LogError(e, $"物料分类数据同步失败, {e.Message}");
            return new Result<int>(e.Message);
        }
    }

    /// <summary>
    /// 同步EAS公司数据<br />
    /// 注意: 该方法只会新增公司数据, 不会删除或修改现有公司数据, 新增的数据默认不会启用. 如果现有数据没有编码, 则会更新编码.
    /// </summary>
    /// <returns></returns>
    public async Task<Result<int>> OrgSync()
    {
        try
        {
            var raw = await dataProvider.GetOrgData();
            var data = await context.DC.Set<SysOrg>()
                .ToListAsync();
            var count = 0;
            foreach (var company in raw)
            {
                var org = data.FirstOrDefault(e => e.Name == company.Name);
                if (org == null)
                {
                    org = new SysOrg();
                    org.Order = 99;
                    org.Name = company.Name;
                    org.Code = company.Code;
                    org.CreateTime = DateTime.Now;
                    org.UpdateTime = DateTime.Now;
                    org.CreateBy = context.LoginUserInfo?.ITCode ?? "system";
                    org.UpdateBy = context.LoginUserInfo?.ITCode ?? "system";
                    await context.DC.Set<SysOrg>().AddAsync(org);
                    count++;
                }
                else
                {
                    if (string.IsNullOrWhiteSpace(org.Code))
                    {
                        org.Code = company.Code;
                        org.UpdateBy = context.LoginUserInfo?.ITCode ?? "system";
                        org.UpdateTime = DateTime.Now;
                        count++;
                    }
                }
            }
            await context.DC.SaveChangesAsync();
            logger.LogInformation("公司数据同步: 成功同步{count}条数据", raw.Length);
            return new Result<int>(count);
        }
        catch (Exception e)
        {
            logger.LogError(e, $"公司数据同步失败, {e.Message}");
            return new Result<int>(e.Message);
        }
    }

    /// <summary>
    /// 同步EAS仓库数据
    /// </summary>
    /// <returns></returns>
    public async Task<Result<int>> WarehouseSync()
    {
        try
        {
            var raw = await dataProvider.GetWarehouseData();
            var data = await context.DC.Set<SysWarehouse>()
                .ToListAsync();
            var count = 0;
            foreach (var warehouse in raw)
            {
                var w = data.FirstOrDefault(e => e.Name == warehouse.Name);
                if (w == null)
                {
                    w = new SysWarehouse();
                    w.Name = warehouse.Name;
                    w.Code = warehouse.Code;
                    w.CreateTime = DateTime.Now;
                    w.UpdateTime = DateTime.Now;
                    w.CreateBy = context.LoginUserInfo?.ITCode ?? "system";
                    w.UpdateBy = context.LoginUserInfo?.ITCode ?? "system";
                    w.CommonState = CommonState.禁用;
                    await context.DC.Set<SysWarehouse>().AddAsync(w);
                    count++;
                }
                else
                {
                    if (string.IsNullOrWhiteSpace(w.ErpId))
                    {
                        w.ErpId = warehouse.Code;
                        w.Code = warehouse.Code;
                        w.UpdateBy = context.LoginUserInfo?.ITCode ?? "system";
                        w.UpdateTime = DateTime.Now;
                        count++;
                    }
                }
            }
            await context.DC.SaveChangesAsync();
            logger.LogInformation("仓库数据同步: 成功同步{count}条数据", raw.Length);
            return new Result<int>(count);
        }
        catch (Exception e)
        {
            logger.LogError(e, $"仓库数据同步失败, {e.Message}");
            return new Result<int>(e.Message);
        }
    }

    /// <summary>
    /// 同步库位
    /// </summary>
    /// <returns></returns>
    public async Task<Result<int>> WarehouseLocationSync()
    {
        try
        {
            var raw = await dataProvider.GetWarehouseLocationData();
            var warehouses = await context.DC.Set<SysWarehouse>()
                .AsNoTracking()
                .Where(e => e.CommonState == CommonState.启用)
                .ToListAsync();
            var areas = await context.DC.Set<SysWarehouseArea>()
                .AsNoTracking()
                .ToListAsync();
            var data = await context.DC.Set<SysWarehouseLocation>()
                .ToListAsync();
            var count = 0;
            foreach (var location in raw)
            {
                var warehouse = warehouses.FirstOrDefault(e => e.Code == location.WarehouseCode);
                if (warehouse == null) continue;
                var area = areas.FirstOrDefault(e => e.Code == location.AreaCode);
                if (area == null)
                {
                    area = new SysWarehouseArea
                    {
                        ID = Uuid.NewDatabaseFriendly(Database.SqlServer),
                        CommonState = CommonState.启用,
                        WarehouseId = warehouse.ID
                    };
                    if (string.IsNullOrWhiteSpace(location.AreaCode))
                    {
                        area.Name = "默认库位";
                    }
                    else
                    {
                        area.Name = location.Name.Contains("区") ? location.Name.Split("区")[0] + "区" : location.Name;
                        area.Code = location.AreaCode;
                    }
                    areas.Add(area);
                    await context.DC.Set<SysWarehouseArea>().AddAsync(area);
                }
                var l = data.FirstOrDefault(e => e.Name == location.Name);
                if (l == null)
                {
                    l = new SysWarehouseLocation();
                    l.ID = Uuid.NewDatabaseFriendly(Database.SqlServer);
                    l.Name = location.Name;
                    l.Code = location.Code;
                    l.ErpId = location.ErpId;
                    l.CommonState = location.CommonState;
                    l.WarehouseId = warehouse.ID;
                    l.AreaId = area.ID;
                    l.CreateTime = DateTime.Now;
                    l.UpdateTime = DateTime.Now;
                    l.CreateBy = context.LoginUserInfo?.ITCode ?? "system";
                    l.UpdateBy = context.LoginUserInfo?.ITCode ?? "system";
                    await context.DC.Set<SysWarehouseLocation>().AddAsync(l);
                    count++;
                }
                else
                {
                    if (string.IsNullOrWhiteSpace(l.ErpId))
                    {
                        l.Code = location.Code;
                        l.ErpId = location.Code;
                        l.UpdateBy = context.LoginUserInfo?.ITCode ?? "system";
                        l.UpdateTime = DateTime.Now;
                        count++;
                    }
                }
            }
            await context.DC.SaveChangesAsync();
            logger.LogInformation("仓库库位数据同步: 成功同步{count}条数据", raw.Length);
            return new Result<int>(count);
        }
        catch (Exception e)
        {
            logger.LogError(e, $"仓库库位数据同步失败, {e.Message}");
            return new Result<int>(e.Message);
        }
    }
    
    
    /// <summary>
    /// 同步库存
    /// </summary>
    /// <returns></returns>
    public async Task<Result<int>> StockSync()
    {
        try
        {
            var raw = await dataProvider.GetWarehouseStockData();
            var data = await context.DC.Set<SysWarehouseStock>()
                .ToListAsync();
            var warehouses = await context.DC.Set<SysWarehouse>()
                .AsNoTracking()
                .Where(e => e.CommonState == CommonState.启用)
                .ToListAsync();
            var locations = await context.DC.Set<SysWarehouseLocation>()
                .AsNoTracking()
                .ToListAsync();
            var skus = await context.DC.Set<SysMaterialSku>()
                .AsNoTracking()
                .ToListAsync();
            var count = 0;
            foreach (var stock in raw)
            {
                var warehouse = warehouses.FirstOrDefault(e => e.Code == stock.WarehouseCode);
                if (warehouse == null) continue;
                var location = locations.FirstOrDefault(e => e.Code == stock.LocationCode);
                if (location == null) continue;
                var sku = skus.FirstOrDefault(e => e.ErpId == stock.MaterialCode);
                if (sku == null) continue;
                var s = data.FirstOrDefault(e => e.LocationId == location.ID && e.SkuId == sku.ID);
                if (s == null)
                {
                    s = new SysWarehouseStock();
                    s.LocationId = location.ID;
                    s.MaterialId = sku.MaterialId;
                    s.SkuId = sku.ID;
                    s.Quantity = stock.Quantity;
                    s.StoreType = stock.StoreType;
                    s.CreateTime = DateTime.Now;
                    s.UpdateTime = DateTime.Now;
                    s.CreateBy = context.LoginUserInfo?.ITCode ?? "system";
                    s.UpdateBy = context.LoginUserInfo?.ITCode ?? "system";
                    await context.DC.Set<SysWarehouseStock>().AddAsync(s);
                    count++;
                }
                else
                {
                    s.Quantity = stock.Quantity;
                    s.UpdateBy = context.LoginUserInfo?.ITCode ?? "system";
                    s.UpdateTime = DateTime.Now;
                    count++;
                }
            }
            await context.DC.SaveChangesAsync();
            logger.LogInformation("库存数据同步: 成功同步{count}条数据", raw.Length);
            return new Result<int>(count);
        }
        catch (Exception e)
        {
            logger.LogError(e, $"库存数据同步失败, {e.Message}");
            return new Result<int>(e.Message);
        }
    }
    
    
    /// <summary>
    /// 同步EAS物料数据
    /// 注意: 该方法会清空现有物料数据, 然后重新同步所有物料数据
    /// </summary>
    /// <returns></returns>
    public async Task<Result<int>> MaterialSync()
    {
        try
        {
            await context.DC.Set<SysRawMaterial>()
                .ExecuteDeleteAsync();
            // 获取所有的物料信息
            var raw = await dataProvider.GetMaterial();
            var allGroup = await context.DC.Set<SysMaterialGroup>()
                .AsNoTracking()
                .ToListAsync();
            var allUnit = await context.DC.Set<SysMeasureUnit>()
                .AsNoTracking()
                .ToListAsync();
            foreach (var material in raw.OrderBy(e => e.Name))
            {
                var group = allGroup.FirstOrDefault(e => e.ErpId == material.GroupCode);
                if (group != null)
                {
                    material.GroupName = group.Name;
                }
                else
                {
                    logger.LogWarning("物料数据同步: 未找到物料所属分组, {@material}", material);
                }
                var unit  = allUnit.FirstOrDefault(e => e.ErpId == material.UnitCode);
                if (unit != null)
                {
                    material.UnitName = unit.Name;
                }
                else
                {
                    logger.LogWarning("物料数据同步: 未找到物料所属计量单位, {@material}", material);
                }
            }
            await context.DC.Set<SysRawMaterial>()
                .AddRangeAsync(raw);
            await context.DC.SaveChangesAsync();
            logger.LogInformation("物料数据同步: 成功同步{count}条数据", raw.Length);
            return new Result<int>(raw.Length);
        }
        catch (Exception e)
        {
            logger.LogError(e, $"物料数据同步失败, {e.Message}");
            return new Result<int>(e.Message);
        }
    }
    
    /// <summary>
    /// 设计一个清洗函数, 出入当前物料 和 相似名称的物料列表. 返回树形的物料数据(让AI扩展物料SKU, 以及物料名称的标准化, 并且返回该树形物料整合后包含的所有名称和型号)
    /// </summary>
    /// <param name="maxConcurrency">最大并发数量，默认为3</param>
    /// <returns></returns>
    public async Task<List<GptMaterial>> CleanMaterial(int maxConcurrency = 1)
    {
        var raw = await context.DC.Set<SysRawMaterial>()
            .AsNoTracking()
            .ToArrayAsync();
        var allGroup = await context.DC.Set<SysMaterialGroup>()
            .Include(e => e.Parent)
            .AsNoTracking()
            .ToListAsync();
        var allUnit = await context.DC.Set<SysMeasureUnit>()
            .AsNoTracking()
            .ToListAsync();
        var groupCodeList = new[] { "2", "7" };
        // 使用 SemaphoreSlim 控制并发数量
        using var semaphore = new SemaphoreSlim(maxConcurrency, maxConcurrency);
        //循环大类
        foreach (var code in groupCodeList)
        {
            // 获取该大类下的所有物料分组
            var groups = allGroup.Where(e => e.Parent != null && e.Parent.Code == code).ToList();
            // 按照物料的最小分组进行循环
            // 这里可以并发执行, 因为物料分组是独立的
            var tasks = groups.Select(group => ProcessMaterialGroup(group, raw, allUnit, semaphore)).ToList();
            // 等待所有任务完成
            await Task.WhenAll(tasks);
        }
        return new List<GptMaterial>();
    }

    
    
    
    /// <summary>
    /// 处理单个物料分组的清洗逻辑
    /// </summary>
    /// <param name="group">物料分组</param>
    /// <param name="raw">原始物料数据</param>
    /// <param name="allUnit">所有计量单位</param>
    /// <param name="semaphore">信号量控制并发</param>
    private async Task AiProcessMaterialGroup(
        SysMaterialGroup group, 
        SysRawMaterial[] raw, 
        List<SysMeasureUnit> allUnit, 
        SemaphoreSlim semaphore)
    {
        await semaphore.WaitAsync();
        // 为每个并发任务创建独立的 scope 和 context
        using var scope = serviceProvider.CreateScope();
        var scopedContext = scope.ServiceProvider.GetRequiredService<WTMContext>();
        try
        {
            var data = raw.Where(e => e.GroupCode == group.ErpId).OrderBy(e => e.Name.Length).ToArray();
            foreach (var element in data)
            {
                var any = await scopedContext.DC.Set<SysMaterialSku>()
                    .AnyAsync(e => e.ErpId == element.Code);
                if(any) continue;
                // 开始循环
                var list = data.Where(e => e.Name.Contains(element.Name) || element.Name.Contains(e.Name)).ToList();
                for (int i = list.Count - 1; i >= 0; i--)
                {
                    var item = list[i];
                    if (await scopedContext.DC.Set<SysMaterialSku>().AnyAsync(e => e.ErpId == item.Code))
                    {
                        list.RemoveAt(i);
                    }
                }
                // 现有的物料只有名称和型号, 并且型号不统一, 名称也有可能不统一, 使用 AI进行清洗
                var views = await AiClearData(list.ToArray());
                if (views == null) continue;
                foreach (var view in views)
                {
                    var transaction = scopedContext.DC.BeginTransaction();
                    try
                    {
                        var material = new SysMaterial
                        {
                            Name = view.Name,
                            Description = view.Description,
                            MaterialGroupId = group.ID,
                            UnitId = allUnit.FirstOrDefault(e => e.Code == element.UnitCode)?.ID,
                            Attributes = [],
                        };
                        var vm = scopedContext.CreateVM<SysMaterialVm>();
                        material.Code = await vm.GenerateCodeAsync(group.ID);
                        foreach (var a in view.Attributes)
                        {
                            var attribute = new SysMaterialAttribute
                            {
                                ID = Uuid.NewDatabaseFriendly(Database.SqlServer),
                                Name = a.Name,
                                Order = 20m,
                                IsKeyAttribute = a.IsKeyAttribute,
                                Values = []
                            };
                            foreach (var v in a.Values)
                            {
                                var value = new SysMaterialAttributeValue
                                {
                                    ID = Uuid.NewDatabaseFriendly(Database.SqlServer),
                                    Value = v,
                                    AttributeId = attribute.ID,
                                    CreateBy = scopedContext.LoginUserInfo?.ITCode ?? "system",
                                    UpdateBy = scopedContext.LoginUserInfo?.ITCode ?? "system",
                                    CreateTime = DateTime.Now,
                                    UpdateTime = DateTime.Now
                                };
                                attribute.Values.Add(value);
                            }

                            material.Attributes.Add(attribute);
                        }
                        await scopedContext.DC.Set<SysMaterial>().AddAsync(material);
                        await scopedContext.DC.SaveChangesAsync();
                        foreach (var sku in view.Skus)
                        {
                            sku.Name = string.Join("/", sku.Attributes.Select(e => e.Value));
                            if (string.IsNullOrWhiteSpace(sku.ErpId))
                            {
                                logger.LogError("AI清洗物料数据失败: SKU的ErpId不能为空, 物料{material}, SKU{@sku}", material.Name, sku);
                                await transaction.RollbackAsync();
                                continue;
                            }

                            if (string.IsNullOrWhiteSpace(sku.Code))
                            {
                                logger.LogError("AI清洗物料数据失败: SKU的Code不能为空, 物料{material}, SKU{@sku}", material.Name, sku);
                                await transaction.RollbackAsync();
                                continue;
                            }

                            var materialSku = new SysMaterialSku();
                            materialSku.ID = Uuid.NewDatabaseFriendly(Database.SqlServer);
                            var rawMaterial = raw.FirstOrDefault(e => e.Code == sku.ErpId);
                            if (rawMaterial == null)
                            {
                                logger.LogError("AI清洗物料数据失败: 未找到对应的原始物料数据, 物料{material}, SKU{@sku}", material.Name, sku);
                                await transaction.RollbackAsync();
                                continue;
                            }
                            var skuVm = scopedContext.CreateVM<SysMaterialSkuVm>();
                            materialSku.Name = sku.Name;
                            materialSku.ErpModel = rawMaterial.Model;
                            materialSku.ErpName = rawMaterial.Name;
                            materialSku.ErpId = sku.ErpId;
                            materialSku.Code = await skuVm.GenerateCodeAsync(material.ID);
                            materialSku.UnitId = allUnit.FirstOrDefault(e => e.Code == sku.ErpId)?.ID ?? material.UnitId;
                            materialSku.MaterialId = material.ID;
                            materialSku.Attributes = new List<SysMaterialSkuAttributes>();
                            foreach (var a in sku.Attributes)
                            {
                                var attribute = material.Attributes.FirstOrDefault(e => e.Name == a.Key);
                                if (attribute == null)
                                {
                                    logger.LogError("AI清洗物料数据失败: 未找到对应的物料属性, 物料{material}, SKU属性{@attribute}",
                                        material.Name, a);
                                    await transaction.RollbackAsync();
                                    continue;
                                }

                                var value = attribute.Values.FirstOrDefault(e => e.Value == a.Value);
                                if (value == null)
                                {
                                    var v = new SysMaterialAttributeValue();
                                    v.Value = a.Value;
                                    v.AttributeId = attribute.ID;
                                    v.Attribute = attribute;
                                    v.ID = Uuid.NewDatabaseFriendly(Database.SqlServer);
                                    v.CreateBy = scopedContext.LoginUserInfo?.ITCode ?? "system";
                                    v.UpdateBy = scopedContext.LoginUserInfo?.ITCode ?? "system";
                                    v.CreateTime = DateTime.Now;
                                    v.UpdateTime = DateTime.Now;
                                    await scopedContext.DC.Set<SysMaterialAttributeValue>().AddAsync(v);
                                    await scopedContext.DC.SaveChangesAsync();
                                    attribute.Values.Add(v);
                                    logger.LogWarning(
                                        "AI清洗物料数据警告: 未找到对应的物料属性值, 系统已自动添加属性值到物料; 物料{material}, SKU属性{name}:{value}",
                                        material.Name, attribute.Name, a.Value);
                                    value = v;
                                }
                                
                                materialSku.Attributes.Add(new SysMaterialSkuAttributes()
                                {
                                    ValueId = value.ID,
                                    SkuId = materialSku.ID,
                                    Value = value
                                });
                                materialSku.Name = string.Join("/",
                                    materialSku.Attributes.Select(e => e.Value.Attribute).Distinct()
                                        .Where(e => e.IsKeyAttribute == true).OrderBy(e => e.Order)
                                        .Select(e => e.Name));
                            }

                            await scopedContext.DC.Set<SysMaterialSku>().AddAsync(materialSku);
                        }

                        await scopedContext.DC.SaveChangesAsync();
                        await transaction.CommitAsync();
                        logger.LogInformation("AI清洗物料数据成功: 保存物料{material}成功", material.Name);
                    }
                    catch (Exception e)
                    {
                        await transaction.RollbackAsync();
                        logger.LogError(e, "AI清洗物料数据失败: 物料{view}, 错误信息: {message}", view.Name, e.Message);
                    }
                    finally
                    {
                        transaction.Dispose();
                    }
                }
            }
        }
        finally
        {
            semaphore.Release();
        }
    }


    /// <summary>
    /// 处理单个物料分组的清洗逻辑
    /// </summary>
    /// <param name="group">物料分组</param>
    /// <param name="raw">原始物料数据</param>
    /// <param name="allUnit">所有计量单位</param>
    /// <param name="semaphore">信号量控制并发</param>
    private async Task ProcessMaterialGroup(
        SysMaterialGroup group, 
        SysRawMaterial[] raw, 
        List<SysMeasureUnit> allUnit, 
        SemaphoreSlim semaphore)
    {
        await semaphore.WaitAsync();
        // 为每个并发任务创建独立的 scope 和 context
        using var scope = serviceProvider.CreateScope();
        var scopedContext = scope.ServiceProvider.GetRequiredService<WTMContext>();
        try
        {
            var data = raw.Where(e => e.GroupCode == group.ErpId).OrderBy(e => e.Name.Length).ToArray();
            foreach (var element in data)
            {
                var any = await scopedContext.DC.Set<SysMaterialSku>()
                    .AnyAsync(e => e.ErpId == element.Code);
                if(any) continue;
                // 开始循环
                var list = data.Where(e => string.Equals(e.Name.Trim(), element.Name.Trim(), StringComparison.OrdinalIgnoreCase)).ToList();
                // 移除已经存在的物料
                for (int i = list.Count - 1; i >= 0; i--)
                {
                    var item = list[i];
                    if (await scopedContext.DC.Set<SysMaterialSku>().AnyAsync(e => e.ErpId == item.Code))
                    {
                        list.RemoveAt(i);
                    }
                }
                // 添加物料和型号
                var vm = scopedContext.CreateVM<SysMaterialVm>();
                var material = new SysMaterial
                {
                    Name = element.Name.Trim(),
                    Description = "",
                    MaterialGroupId = group.ID,
                    UnitId = allUnit.FirstOrDefault(e => e.Code == element.UnitCode)?.ID,
                    Attributes = [],
                };
                material.Code = await vm.GenerateCodeAsync(group.ID);
                var attribute = new SysMaterialAttribute
                {
                    ID = Uuid.NewDatabaseFriendly(Database.SqlServer),
                    Name = "型号",
                    Order = 20m,
                    IsKeyAttribute = true,
                    Values = []
                };
                foreach (var item in list)
                {
                    var value = new SysMaterialAttributeValue
                    {
                        ID = Uuid.NewDatabaseFriendly(Database.SqlServer),
                        Value = item.Model.Trim(),
                        AttributeId = attribute.ID,
                        CreateBy = scopedContext.LoginUserInfo?.ITCode ?? "system",
                        UpdateBy = scopedContext.LoginUserInfo?.ITCode ?? "system",
                        CreateTime = DateTime.Now,
                        UpdateTime = DateTime.Now
                    };
                    attribute.Values.Add(value);
                }
                material.Attributes.Add(attribute);
                await scopedContext.DC.Set<SysMaterial>().AddAsync(material);
                await scopedContext.DC.SaveChangesAsync();
                //添加 SKU
                foreach (var item in list)
                {
                    var materialSku = new SysMaterialSku();
                    materialSku.ID = Uuid.NewDatabaseFriendly(Database.SqlServer);
                    var skuVm = scopedContext.CreateVM<SysMaterialSkuVm>();
                    materialSku.Name = item.Name;
                    materialSku.ErpModel = item.Model;
                    materialSku.ErpName = item.Name;
                    materialSku.ErpId = item.Code;
                    materialSku.Code = await skuVm.GenerateCodeAsync(material.ID);
                    materialSku.UnitId = allUnit.FirstOrDefault(e => e.Code == item.UnitCode)?.ID ?? material.UnitId;
                    materialSku.MaterialId = material.ID;
                    materialSku.Attributes = new List<SysMaterialSkuAttributes>();
                    var value = attribute.Values.FirstOrDefault(e => e.Value == item.Model.Trim());
                    if (value == null)
                    {
                        logger.LogError("物料数据处理失败: 未找到对应的物料属性值, 物料{material}, SKU属性{@attribute}", material.Name, item.Model);
                        continue;
                    }
                    materialSku.Attributes.Add(new SysMaterialSkuAttributes()
                    {
                        ValueId = value.ID,
                        SkuId = materialSku.ID,
                        Value = value
                    });
                    materialSku.Name = string.Join("/",
                        materialSku.Attributes.Select(e => e.Value)
                            .Where(e => e.Attribute.IsKeyAttribute)
                            .OrderBy(e => e.Attribute.Order)
                            .Select(e => $"{e.Attribute.Name}:{e.Value}"));
                    materialSku.Name = $"物料:{material.Name}/{materialSku.Name}";
                    await scopedContext.DC.Set<SysMaterialSku>().AddAsync(materialSku);
                }
                await scopedContext.DC.SaveChangesAsync();
                logger.LogInformation("物料数据处理成功: 保存物料{material}成功, 合并物料{count}个", material.Name, list.Count);
            }
        }
        finally
        {
            semaphore.Release();
        }
    }

    
    
    
    private async Task<GptMaterial[]> AiClearData(SysRawMaterial[] materials)
    {
        try
        {
            //系统提示词
            var systemPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Services", "系统提示词.md");
            var userPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Services", "用户提示词.md");

            var system = await File.ReadAllTextAsync(systemPath);
            var user = await File.ReadAllTextAsync(userPath);
            var options = new JsonSerializerOptions()
            {
                //禁止UNICODE编码
                Encoder = System.Text.Encodings.Web.JavaScriptEncoder.UnsafeRelaxedJsonEscaping
            };
            var data = JsonSerializer.Serialize(materials, options);
            //移除ID字段，减少数据传输量
            data = Regex.Replace(data, @",""ID"":""[0-9a-fA-F\-]+""", "");
            user = user.Replace("[这里粘贴您的物料数据列表]", data);
            
            // 初始请求
            var response = await GptChatWithContinue(system, user);
            if (response.Code == 200)
            {
                var fullContent = response.Data;
                
                // 尝试解析完整的JSON
                if(!fullContent.TryJsonParse(out List<GptMaterial> result, out var error))
                {
                    logger.LogError(error, "AI清洗物料数据失败: 返回结果无法解析为物料数据列表, 返回内容: {content}", fullContent);
                    return null;
                }
                
                logger.LogInformation("AI清洗成功，输入 {input} 条数据，输出 {output} 条整合后的物料", materials.Length, result.Count);
                return result.ToArray();
            }
            else
            {
                logger.LogError("AI清洗物料数据失败: {message}", response.Message);
                return null;
            }
        }
        catch (Exception e)
        {
            logger.LogError(e, "AI清洗物料数据失败: {message}", e.Message);
            return null;
        }
    }
    
    /// <summary>
    /// 支持continue机制的GPT聊天，自动处理不完整的JSON响应
    /// </summary>
    private async Task<Result<string>> GptChatWithContinue(string system, string user)
    {
        const int maxContinueAttempts = 5; // 最多continue 3次
        var messageHistory = new List<ChatMessage>
        {
            ChatMessage.FromSystem(system),
            ChatMessage.FromUser(user)
        };
        
        string combinedContent = "";
        int continueCount = 0;
        
        while (continueCount <= maxContinueAttempts)
        {
            var chatResult = await GptChat(messageHistory);
            
            if (chatResult.Code != 200)
            {
                return new Result<string>(chatResult.Message);
            }
            
            var currentContent = chatResult.Data.Last().Content;
            
            if (string.IsNullOrEmpty(currentContent))
            {
                logger.LogWarning("AI返回内容为空");
                return new Result<string>("AI返回内容为空");
            }
            
            // 累积内容
            if (continueCount == 0)
            {
                combinedContent = currentContent;
            }
            else
            {
                // continue的内容直接拼接（移除可能重复的开头字符）
                combinedContent += currentContent.TrimStart();
            }
            
            // 检查JSON是否完整有效
            if (IsValidJson(combinedContent))
            {
                logger.LogInformation("JSON数据完整有效，共进行了 {count} 次continue", continueCount);
                return new Result<string>
                {
                    Data = combinedContent
                };
            }
            
            // JSON不完整，尝试continue
            if (continueCount < maxContinueAttempts)
            {
                logger.LogInformation("JSON数据不完整，发送第 {count} 次continue请求", continueCount + 1);
                
                // 将AI的响应加入历史
                messageHistory.Add(ChatMessage.FromAssistant(currentContent));
                
                // 发送continue消息
                messageHistory.Add(ChatMessage.FromUser("continue"));
                
                continueCount++;
                await Task.Delay(500); // 短暂延迟
            }
            else
            {
                // 达到最大continue次数，返回错误
                logger.LogError("已达到最大continue次数 {max}，JSON数据仍然不完整: {@content}", maxContinueAttempts, combinedContent);
                return new Result<string>("JSON数据不完整，已达到最大continue次数");
            }
        }
        
        return new Result<string>("未知错误");
    }
    
    /// <summary>
    /// 使用 System.Text.Json 检查 JSON 是否完整且有效
    /// </summary>
    /// <param name="json">JSON字符串</param>
    /// <returns>是否为完整有效的JSON</returns>
    private bool IsValidJson(string json)
    {
        if (string.IsNullOrWhiteSpace(json))
        {
            return false;
        }
        
        try
        {
            // 使用 JsonDocument 验证 JSON 是否完整有效
            using var document = JsonDocument.Parse(json);
            // 如果能成功解析，说明 JSON 完整有效
            return true;
        }
        catch (JsonException ex)
        {
            // JSON 格式错误或不完整
            logger.LogWarning("JSON数据无效: {message}", ex.Message);
            return false;
        }
    }
    
    /// <summary>
    /// GPT对话，支持传入完整的消息历史（用于continue机制）
    /// </summary>
    public async Task<Result<List<ChatMessage>>> GptChat(List<ChatMessage> messages, int? maxTokens = null)
    {
        var httpClient = new HttpClient();
        httpClient.Timeout = TimeSpan.FromMinutes(10);
        var openAiService = new OpenAIService(new OpenAIOptions()
        {
            ApiKey = "sk-d0b536968d5d46b0b8e8fa60dd8c1f6d",
            BaseDomain = "https://api.deepseek.com/v1"
        }, httpClient);
        
        var chatRequest = new ChatCompletionCreateRequest
        {
            Messages = messages,
            Model = "deepseek-chat",
            MaxTokens = maxTokens ?? 8192,
            ResponseFormat = new ResponseFormat{
                Type = "json_object"
            }
        };
        var completionResult = await openAiService.ChatCompletion.CreateCompletion(chatRequest);
        if (completionResult.Successful)
        {
            var response = completionResult.Choices.First().Message.Content;
            if (!string.IsNullOrWhiteSpace(response))
            {
                messages.Add(ChatMessage.FromAssistant(response));
                return new Result<List<ChatMessage>>()
                {
                    Data = messages
                };
            }
            else
            {
                return new Result<List<ChatMessage>>("返回内容为空");
            }
        }
        else
        {
            return new Result<List<ChatMessage>>(completionResult.Error?.Message ?? "未知错误");
        }
    }
    
    
}
